#include <pthread.h>
#include <rid.h>
#include <stdint.h>
#include <stdlib.h>

#include <nit/macros.h>
#include <nit/palloc.h>
#include <nit/list.h>
#include <nit/set.h>
#include <nit/map.h>

#include <oas.h>

#include "pum.h"
#include "global.h"

typedef struct Pum_list Pum_list;

struct Pum_list {
	union {
		Pum_val val;
		Pum_list *next;
	} u;
};

typedef struct {
	Pum_list *pums;
	pthread_mutex_t pum_mutex;
} Globe;

int
global_init(Oas_sys *sys)
{
	Globe *globe = palloc(globe);

	pcheck(globe, -1);

	if (pthread_mutex_init(&globe->pum_mutex, NULL)) {
		free(globe);
		return -1;
	}

	globe->pums = NULL;
	sys->global = globe;
	return 0;
}

Pum_val *
global_get_pum(Oas_sys *sys)
{
	Globe *globe = sys->global;
	Pum_list *list;

	pthread_mutex_lock(&globe->pum_mutex);

	if ((list = globe->pums))
		globe->pums = list->u.next;
	else
		list = palloc(list);

	pthread_mutex_unlock(&globe->pum_mutex);
	return (Pum_val *) list;
}

void
global_recycle_pum(Oas_sys *sys, Pum_val *val)
{
	Globe *globe = sys->global;
	Pum_list *list = (Pum_list *) val;

	pthread_mutex_lock(&globe->pum_mutex);
	list->u.next = globe->pums;
	globe->pums = list;
	pthread_mutex_unlock(&globe->pum_mutex);
}

void
global_dispose(Oas_sys *sys)
{
	Globe *globe = sys->global;
	Pum_list *list = globe->pums;

	while (list) {
		Pum_list *tmp = list;

		list = list->u.next;
		free(tmp);
	}

	pthread_mutex_destroy(&globe->pum_mutex);
	free(globe);
}
